Railsアプリでセキュアなパスワードを使う

目次

Railsアプリでセキュアなパスワードを使用する方法 +α 。


準備

gem追加

Gemfileを修正し、bundle installします。
Railsアプリをrails newで作成後に特に消していなければ、Blowfish暗号を利用できるbcryptというgemがコメントアウトされているはずです。 これをアンコメントします。

## 省略 ##

- # gem 'bcrypt', '~> 3.1.7'
+ gem 'bcrypt', '~> 3.1.7'

## 省略 ##
bundle install

実装

セキュアなパスワードは has_secure_password というメソッドを、生成されるmodelで呼び出します。
このメソッドを使うためには、モデル内にpassword_digestという属性が含まれている必要があるため注意します。

モデル作成

rails g model User name:string email:string password_digest:string

modelファイル編集

app/models/user.rbに下記を追加します。

class User < ApplicationRecord

  before_save { email.downcase! }

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.freeze
  # 半角英数字大文字小文字をそれぞれ1文字以上含む
  VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,16}+\z/.freeze

  validates :name,
            presence: true,
            length: { in: 1..30 }

  validates :email,
            presence: true,
            format: { with: VALID_EMAIL_REGEX },
            uniqueness: { case_sensitive: false }

  has_secure_password
  validates :password,
            presence: true,
            length: { minimum: 8 },
            format: { with: VALID_PASSWORD_REGEX }
end

Migration

$ rails db:migrate
      invoke  active_record
      create    db/migrate/20190829085116_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml

確認

User.newで作成したオブジェクトをsaveメソッドで保存。
ハッシュ化されたパスワードが登録されていることを確認します。

$ rails c
Loading development environment (Rails 5.2.3)

irb(main):001:0> user = User.new(name: "kohbis", email: "tEst@test.com", password: "Passw0rd")
=> #<User id: nil, name: "kohbis", email: "tEst@test.com", password_digest: "$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.1...", created_at: nil, updated_at: nil>

irb(main):002:0> user.save
   (0.9ms)  BEGIN
  User Exists (1.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'tEst@test.com' LIMIT 1
  User Create (0.5ms)  INSERT INTO `users` (`name`, `email`, `password_digest`, `created_at`, `updated_at`) VALUES ('kohbis', 'test@test.com', '$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.18p.sIGQ/Ce', '2019-08-29 12:39:14', '2019-08-29 12:39:14')
   (2.2ms)  COMMIT
=> true

irb(main):003:0> User.all
  User Load (0.9ms)  SELECT  `users`.* FROM `users` LIMIT 11
=> #<ActiveRecord::Relation [#<User id: 1, name: "kohbis", email: "test@test.com", password_digest: "$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.1...", created_at: "2019-08-29 12:39:14", updated_at: "2019-08-29 12:39:14">]>

最後にvalidationが効いているかも確認しておきます。

$ rails c
Loading development environment (Rails 5.2.3)
irb(main):001:0> user = User.new(name: "", email: "@not.address", password: "password")
   (0.6ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
=> #<User id: nil, name: "", email: "@not.address", password_digest: "$2a$12$5PovSBWfHCPDOKQcD3lCAuOC7YepZvIwIaocF01tEI5...", created_at: nil, updated_at: nil>

irb(main):002:0> user.valid?
  User Exists (0.5ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = '@not.address' LIMIT 1
=> false

irb(main):003:0> user.errors.messages
=> {:name=>["can't be blank", "is too short (minimum is 1 character)"], :email=>["is invalid"], :password=>["is invalid"]}

以上。

← Posts